package com.kmxd.ams.app.arrange.command;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.google.common.collect.Maps;
import com.kmxd.ams.client.archive.IArchiveRuleMainSvc;
import com.kmxd.ams.client.archive.IArchiveTypeSvc;
import com.kmxd.ams.client.archive.dto.RuleFieldQueryDTO;
import com.kmxd.ams.client.archive.vo.ArchiveRuleFieldListVO;
import com.kmxd.ams.client.archive.vo.ArchiveRuleMainListVO;
import com.kmxd.ams.client.archive.vo.ArchiveTypeVO;
import com.kmxd.ams.client.arrange.IDocumentSvc;
import com.kmxd.ams.client.arrange.IProjectSvc;
import com.kmxd.ams.client.arrange.IVolumeSvc;
import com.kmxd.ams.client.arrange.dto.VolumeBuildUpDTO;
import com.kmxd.ams.client.arrange.vo.ArchCodeVO;
import com.kmxd.ams.client.arrange.vo.InVolumeVO;
import com.kmxd.ams.core.common.constant.ArchConst;
import com.kmxd.ams.core.common.constant.ErrorCode;
import com.kmxd.ams.core.common.enums.ArchStatusEnum;
import com.kmxd.ams.core.common.enums.RuleFieldTypeEnum;
import com.kmxd.ams.core.common.enums.VolumeDocAutoCodeEnum;
import com.kmxd.ams.core.exception.BizTipException;
import com.kmxd.ams.core.exception.DataCheckException;
import com.kmxd.ams.core.util.ConvertUtil;
import com.kmxd.ams.core.util.SecurityUtil;
import com.kmxd.ams.infra.archive.entity.ArchiveRuleMain;
import com.kmxd.ams.infra.archive.entity.ArchiveType;
import com.kmxd.ams.infra.arrange.base.BaseBO;
import com.kmxd.ams.infra.arrange.entity.Document;
import com.kmxd.ams.infra.arrange.entity.Project;
import com.kmxd.ams.infra.arrange.entity.Volume;
import com.kmxd.ams.infra.tmpl.dto.ArchTmplBO;
import com.kmxd.ams.infra.utils.GroupUtil;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

/**
 * 组卷
 *
 * @author nickbi
 */
@Slf4j
@AllArgsConstructor
@Component
public class InVolumeCmd {
  private final IVolumeSvc volumeSvc;
  private final IDocumentSvc documentSvc;
  private final IArchiveRuleMainSvc archiveRuleMainSvc;
  private final ArchCodeGenCmd archCodeGenCmd;
  private final ExtendDataCmd extendDataCmd;
  private final IProjectSvc projectSvc;
  private final IArchiveTypeSvc archiveTypeSvc;
  private final ArchSortCmd archSortCmd;

  /**
   * 组卷 1.自动组卷 2.加入当前案卷 3. 加入指定案卷
   *
   * @param req
   * @return
   */
  @Transactional(rollbackFor = Exception.class)
  public List<InVolumeVO> inVolume(VolumeBuildUpDTO req) {
    // 1.自动组卷
    switch (req.getType()) {
      case AUTO:
        return autoInVolume(req);
      case JOIN_SELECTED:
        return selected(req);
      default:
        throw BizTipException.instance(ErrorCode.NOT_FOUND, "未知类型");
    }
  }

  public List<InVolumeVO> autoInVolume(VolumeBuildUpDTO req) {

    BaseBO baseBO = BeanUtil.copyProperties(req, BaseBO.class);
    baseBO.setDocIds(req.getDocIds());
    baseBO.setTableId(req.getDocTableId());
    List<Document> documentList = documentSvc.selectListByIds(baseBO);
    if (ObjectUtil.isEmpty(documentList)) {
      return Lists.newArrayList();
    }
    // 检测数据是否包含年度，整理规则与年度挂钩（除项目类）
//    List<String> fondsList =
//        documentList.stream().map(SystemBO::getFondsCode).collect(Collectors.toList());
//    if (ObjectUtil.isNotEmpty(fondsList) && fondsList.size() > 1) {
//      throw BizTipException.instance(ErrorCode.FONDS_CODE_NOT_EQUAL, "全宗号不一致，无法组卷");
//    }
    
    checkYear(documentList, req.getProjId(), null, null);
    ArchiveRuleMain ruleInfo =
        getRuleInfo(req.getArchTypeId(), req.getProjId(), documentList.get(0).getYear());
    RuleFieldQueryDTO ruleFieldQueryDTO = new RuleFieldQueryDTO();
    ruleFieldQueryDTO.setArchTypeId(req.getArchTypeId());
    ruleFieldQueryDTO.setRuleId(ruleInfo.getId());

    List<ArchiveRuleFieldListVO> ruleFieldList =
        archiveRuleMainSvc.getRuleFieldByVersion(ruleFieldQueryDTO);
    if (ObjectUtil.isEmpty(ruleFieldList)) {
      throw BizTipException.instance(ErrorCode.NOT_FOUND, "未找到规则信息");
    }
    // 按分组字段条件，直接将数据分组， stream 嵌套group 会有展开的问题，如 Map<year,Map<classfy,List<Document>>>
    // 最佳方案，key为 分组信息，value为分好组的数据信息 Map<key,List<Document>>
    // 存在不符合分组规则的数据，直接返回前端错误数据信息
    List<ArchiveRuleFieldListVO> volumeRuleList =
        ruleFieldList.stream()
            .filter(f -> f.getTableId().contains(ArchTmplBO.VOLUME))
            .filter(f -> !f.getFieldCode().contains(ArchConst.SEQUENSE))
            .filter(ArchiveRuleFieldListVO::getEnableGroup)
            .collect(Collectors.toList());
    Map<List<Object>, List<Document>> collect =
        documentList.stream()
            .collect(
                Collectors.groupingBy(
                    document -> GroupUtil.buildKey(document, volumeRuleList), Collectors.toList()));
    ArchiveType archType = archiveTypeSvc.getById(req.getArchTypeId());
    if (archType.getHaveProject()) {
      Project qryProj = new Project();
      qryProj.setArchTypeId(req.getArchTypeId());
      qryProj.setTableId(archType.getProjTableId());
      qryProj.setId(req.getProjId());
      Project project = projectSvc.view(qryProj);
      checkDataWithRule(project, collect, volumeRuleList);
    } else {
      checkDataWithRule(null, collect, volumeRuleList);
    }

    Map<List<Object>, List<Document>> nonNullMap = groupByPredicate(collect, Objects::nonNull);
    ArchiveRuleMain archRule =
        Optional.ofNullable(archiveRuleMainSvc.getById(ruleFieldList.get(0).getRuleId()))
            .orElseThrow(() -> BizTipException.instance(ErrorCode.NOT_FOUND, "整理规则未找到"));
    Document doc = documentList.isEmpty() ? null : documentList.get(0);

    nonNullMap.forEach(
        (groupFieldKey, list) -> {
          Volume volume = new Volume();
          volume.setTableId(req.getTableId());
          String title =
              groupFieldKey.stream().map(Objects::toString).collect(Collectors.joining("-"));
          volume.setTitle(title);
          Map<String, Object> volumeMap = BeanUtil.beanToMap(volume);
          AtomicInteger index = new AtomicInteger(0);
          volumeRuleList.forEach(
              field -> {
                String fieldCode = field.getFieldCode();
                volumeMap.put(
                    StringUtils.underlineToCamel(fieldCode),
                    groupFieldKey.get(index.getAndIncrement()));
              });
          BeanUtil.copyProperties(volumeMap, volume, CopyOptions.create().ignoreNullValue());
          volume.setArchTypeId(req.getArchTypeId());
          volume.setProjId(req.getProjId());
          Map<String, Object> extendData = extendDataCmd.buildExtendData(volume);
          BeanUtil.copyProperties(extendData, volume, CopyOptions.create().ignoreNullValue());
          volume.setTableId(req.getTableId());
          buildVolumeArchCode(volume, archRule);
          volume.setStatus(ArchStatusEnum.S0.getCode());
          volume.setYear(ObjectUtil.isNotEmpty(doc) ? doc.getYear() : null);
          volume.setRetentionPeriod(ObjectUtil.isNotEmpty(doc) ? doc.getRetentionPeriod() : null);
          volume.setClassfyName(ObjectUtil.isNotEmpty(doc) ? doc.getClassfyName() : null);

          volume.setManageStatus(
              ObjectUtil.isNotEmpty(volume.getManageStatus())
                  ? volume.getManageStatus()
                  : SecurityUtil.getManageStatus());
          volumeSvc.add(volume);
          // 获取序号时回+1，然后重新设置sequence，所以新建的案卷下的文档index以0开始，获取档号后会按1开始
          archSortCmd.sortDocumentList(req, list);
          if (Objects.nonNull(volume.getArchCode())) {
            AtomicInteger documentIndex = new AtomicInteger(1);
            list.forEach(
                document ->
                    editDocument(req, archRule, volume, documentIndex.getAndIncrement(), document));
          }
        });
    return Lists.newArrayList();
  }

  private void editDocument(
      VolumeBuildUpDTO req,
      ArchiveRuleMain archRule,
      Volume volume,
      Integer documentIndex,
      Document document) {
    document.setArchTypeId(req.getArchTypeId());
    document.setDocSequence(documentIndex);
    document.setTableId(req.getDocTableId());
    document.setVolId(volume.getId());
    Map<String, Object> extendMap = extendDataCmd.buildExtendData(document);
    BeanUtil.copyProperties(extendMap, document);
    buildDocumentArchCode(volume, archRule, document);
    documentSvc.edit(document);
  }

  public Map<List<Object>, List<Document>> groupByPredicate(
      Map<List<Object>, List<Document>> dataMap, Predicate<? super Object> predicate) {
    return dataMap.entrySet().stream()
        .filter(
            ruleKey -> {
              List<Object> nonNullKeyList =
                  ruleKey.getKey().stream().filter(predicate).collect(Collectors.toList());
              return !nonNullKeyList.isEmpty();
            })
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
  }

  /**
   * 按整理规则，教育组卷/装盒数据，项目级需要特殊处理，项目级没有的数据即使有规则也不进行校验
   *
   * @param dataMap
   * @param ruleFieldList
   */
  public void checkDataWithRule(
      Project project,
      Map<List<Object>, List<Document>> dataMap,
      List<ArchiveRuleFieldListVO> ruleFieldList) {
    Map<List<Object>, List<Integer>> nullKeyMap = Maps.newHashMap();
    dataMap.entrySet().stream()
        .filter(
            ruleKey -> {
              List<Integer> errorList = Lists.newArrayList();

              if (Objects.isNull(project)) {
                AtomicInteger count = new AtomicInteger(0);

                // 过滤key为空的数据,
                List<Object> nullKeyList =
                    ruleKey.getKey().stream()
                        .filter(
                            item -> {
                              boolean flag = Objects.isNull(item);
                              int index = count.getAndIncrement();
                              if (flag) {
                                errorList.add(index);
                              }
                              return flag;
                            })
                        .collect(Collectors.toList());
                if (ObjectUtil.isNotEmpty(errorList)) {
                  nullKeyMap.put(ruleKey.getKey(), errorList);
                }
                return !nullKeyList.isEmpty();
              }
              // 项目级的案卷进行组卷等操作，
              AtomicInteger count = new AtomicInteger(0);
              Map<String, Object> projMap = BeanUtil.beanToMap(project);
              List<Object> projNullKeyList =
                  ruleKey.getKey().stream()
                      .filter(
                          item -> {
                            int index = count.getAndIncrement();
                            ArchiveRuleFieldListVO field = ruleFieldList.get(index);
                            // 文件级 项目级字段不相同
                            String camelField = StringUtils.underlineToCamel(field.getFieldCode());
                            boolean flag = projMap.containsKey(camelField);
                            if (!flag) {
                              boolean aNull = Objects.isNull(item);
                              if (aNull) {
                                errorList.add(index);
                              }
                              return aNull;
                            }
                            // 文件级项目级字段相同，并且值相同，则不返回字段数据校验不通过问题
                            boolean notEqual = ObjectUtil.notEqual(item, projMap.get(camelField));
                            if (notEqual) {
                              errorList.add(index);
                            }
                            return notEqual;
                          })
                      .collect(Collectors.toList());
              if (ObjectUtil.isNotEmpty(errorList)) {
                nullKeyMap.put(ruleKey.getKey(), errorList);
              }
              return !projNullKeyList.isEmpty();
            })
        .forEach(
            // 空字段信息，拼接提示用户
            entry -> {
              List<Object> key = entry.getKey();
              // 校验不通过字段index值
              List<Integer> nullKeyIndexList = nullKeyMap.get(key);
              // 拼接数据为空的字段信息，提示用户
              String errorMsg =
                  nullKeyIndexList.stream()
                      .map(
                          index -> {
                            ArchiveRuleFieldListVO fieldListVO = ruleFieldList.get(index);
                            return fieldListVO.getFieldName();
                          })
                      .collect(Collectors.joining(","));
              throw BizTipException.instance(ErrorCode.VALIDATE_ERROR, errorMsg + "不能为空");
            });
  }

  public void checkYear(
      List<Document> documentList, Long archRuleId, Boolean syncVolume, Volume joinVolume) {
    if (Objects.nonNull(archRuleId)) {
      return;
    }

    // 选择的数据大于两个年度的直接返回
    Map<Optional<Integer>, List<Document>> yearGroup =
        documentList.stream()
            .collect(
                Collectors.groupingBy(d -> Optional.ofNullable(d.getYear()), Collectors.toList()));
    if (null != yearGroup && yearGroup.size() > 1) {
      throw BizTipException.instance(ErrorCode.DATA_NOT_IN_SAME_GROUP, "检测到条目的分组数据不一致");
    }
    // 加入案卷，并且选择的案卷没有年度信息，直接使用默认规则进行数据校验
    if (null != joinVolume && null == joinVolume.getYear()) {
      return;
    }
    // 数据校验后，用户选择同步案卷信息，直接返回，不校验案卷跟文件年度信息
    if (BooleanUtil.isTrue(syncVolume)) {
      return;
    }
    // 加入案卷
    if (null != joinVolume) {
      Document document = documentList.get(0);
      if (!ObjectUtil.equals(document.getYear(), joinVolume.getYear())) {
        // 文件和案卷年度不一致，直接报错
        throw DataCheckException.instance(ErrorCode.DATA_NOT_IN_SAME_GROUP, "检测到条目的分组数据不一致");
      }
    }
  }

  /**
   * 加入指定案卷中
   *
   * @param req
   * @return
   */
  public List<InVolumeVO> selected(VolumeBuildUpDTO req) {
    if (null == req.getId()) {
      throw BizTipException.instance(ErrorCode.VALIDATE_ERROR, "案卷id不能为空");
    }
    Volume qry = new Volume();
    qry.setTableId(req.getTableId());
    qry.setId(req.getId());
    Volume volume =
        Optional.ofNullable(volumeSvc.view(qry))
            .orElseThrow(() -> BizTipException.instance(ErrorCode.NOT_FOUND, "未找到案卷信息"));

    BaseBO baseBO = BeanUtil.copyProperties(req, BaseBO.class);
    baseBO.setDocIds(req.getDocIds());
    baseBO.setTableId(req.getDocTableId());
    List<Document> documentList = documentSvc.selectListByIds(baseBO);
    if (ObjectUtil.isEmpty(documentList)) {
      return Lists.newArrayList();
    }
    // 检测数据是否包含年度，整理规则与年度挂钩（除项目类）
    checkYear(documentList, req.getProjId(), req.getSyncVolume(), volume);
    ArchiveRuleMain archRule = getRuleInfo(req.getArchTypeId(), req.getProjId(), volume.getYear());
    RuleFieldQueryDTO ruleFieldQueryDTO = new RuleFieldQueryDTO();
    ruleFieldQueryDTO.setArchTypeId(req.getArchTypeId());
    ruleFieldQueryDTO.setRuleId(archRule.getId());
    List<ArchiveRuleFieldListVO> ruleFieldList =
        archiveRuleMainSvc.getRuleFieldByVersion(ruleFieldQueryDTO);
    if (ObjectUtil.isEmpty(ruleFieldList)) {
      throw BizTipException.instance(ErrorCode.NOT_FOUND, "未找到规则信息");
    }

    // 按分组字段条件，直接将数据分组， stream 嵌套group 会有展开的问题，如 Map<year,Map<classfy,List<Document>>>
    // 最佳方案，key为 分组信息，value为分好组的数据信息 Map<key,List<Document>>
    List<ArchiveRuleFieldListVO> fieldSet =
        ruleFieldList.stream()
            .filter(f -> f.getTableId().contains(ArchTmplBO.VOLUME))
            .filter(ArchiveRuleFieldListVO::getEnableGroup)
            .filter(f -> !f.getFieldCode().contains(ArchConst.SEQUENSE))
            .collect(Collectors.toList());
    // 直接复制案卷分组信息到文件
    Document qrySequence = new Document();
    qrySequence.setTableId(req.getDocTableId());
    qrySequence.setVolId(volume.getId());
    // 构建分组条件信息

    Map<String, Object> columnMap = new HashMap<>();
    // 生成拼接部分内容
    fieldSet.stream()
        .filter(ArchiveRuleFieldListVO::getEnableBoxGroup)
        .filter(f -> !f.getFieldCode().contains(ArchConst.SEQUENSE))
        .forEach(
            item -> {
              if (!NumberUtil.equals(RuleFieldTypeEnum.FIXED.getCode(), item.getType())) {
                JSONObject jsonObject = JSONUtil.parseObj(volume);
                String fieldKey =
                    !StringUtils.isCamel(item.getFieldCode())
                        ? StringUtils.underlineToCamel(item.getFieldCode())
                        : item.getFieldCode();
                String value = jsonObject.getStr(fieldKey);
                if (StrUtil.isNotBlank(value)) {
                  columnMap.put(item.getFieldCode(), value);
                }
              }
            });

    Integer nextDocSequence =
        documentSvc.getMaxDocSequence(columnMap, qrySequence.getTableId(), false);
    Map<List<Object>, List<Document>> collect =
        documentList.stream()
            .collect(
                Collectors.groupingBy(
                    document -> GroupUtil.buildKey(document, fieldSet), Collectors.toList()));
    // 存在不符合分组规则的数据，直接返回前端错误数据信息
    // 校验时，如果数据分组大于1，说明数据分组不一致，直接提示用户分组信息不一致，
    // 有复制案卷信息到所有文件的flag时，不进行该校验，直接修改文件信息
    if (BooleanUtil.isFalse(req.getSyncVolume())) {
      checkJoinVolumeData(volume, fieldSet, collect);
    }
    if (BooleanUtil.isTrue(req.getSyncVolume())) {
      Map<String, Object> syncVolumeMap = getSyncVolumeData(ruleFieldList, volume);

      AtomicInteger documentIndex = new AtomicInteger(nextDocSequence);
      documentList.forEach(
          document -> {
            BeanUtil.copyProperties(syncVolumeMap, document);
            editDocument(req, archRule, volume, documentIndex.getAndIncrement(), document);
          });
      return Lists.newArrayList();
    }

    collect.forEach(
        (rule, list) -> {
          // 如果当前案卷没有档号信息，则匹配与案卷相关的信息，
          // 如果有档号信息，则生成文件档号
          AtomicInteger documentIndex = new AtomicInteger(nextDocSequence);
          // 设置排序信息
          archSortCmd.sortDocumentList(req, list);
          list.forEach(
              document ->
                  editDocument(req, archRule, volume, documentIndex.getAndIncrement(), document));
        });
    return Lists.newArrayList();
  }

  private void checkJoinVolumeData(
      Volume volume,
      List<ArchiveRuleFieldListVO> fieldSet,
      Map<List<Object>, List<Document>> collect) {
    if (collect.entrySet().size() > 1) {
      throw DataCheckException.instance(ErrorCode.DATA_NOT_IN_SAME_GROUP, "检测到条目的分组数据不一致");
    }
    Map<String, Object> volumeMap = BeanUtil.beanToMap(volume);
    List<Object> volumeGroupList =
        fieldSet.stream()
            .map(field -> volumeMap.get(StringUtils.underlineToCamel(field.getFieldCode())))
            .collect(Collectors.toList());
    collect.forEach(
        (dataGroupList, value) -> {
          if (!dataGroupList.equals(volumeGroupList)) {
            AtomicInteger index = new AtomicInteger(0);
            String errorMsg =
                fieldSet.stream()
                    .map(
                        field -> {
                          int currentIndex = index.getAndIncrement();
                          if (ObjectUtil.notEqual(
                              volumeGroupList.get(currentIndex), dataGroupList.get(currentIndex))) {
                            return field.getFieldName();
                          }
                          return "";
                        })
                    .filter(StrUtil::isNotBlank)
                    .collect(Collectors.joining(","));
            throw BizTipException.instance(ErrorCode.VALIDATE_ERROR, errorMsg + " 与加入案卷数据不一致");
            //            throw DataCheckException.instance(ErrorCode.DATA_NOT_IN_SAME_GROUP,
            // "检测到条目的分组数据不一致");
          }
        });
  }

  public void buildDocumentArchCode(Volume volume, ArchiveRuleMain archRule, Document document) {
    // 案卷号不为空，并且卷内文件为自动编号或按设置字段编号
    if (StrUtil.isBlank(volume.getArchCode())) {
      document.setArchCode(null);
      document.setDocSequence(null);
      return;
    }

    if (VolumeDocAutoCodeEnum.MANUAL.getCode().equals(archRule.getVolAutoCode())) {
      return;
    }

    ArchCodeVO archCodeVO = archCodeGenCmd.archCode(document);
    document.setArchCode(archCodeVO.getArchCode());
    document.setDocSequence(archCodeVO.getSequence());
  }

  public void buildVolumeArchCode(Volume volume, ArchiveRuleMain archRule) {
    if (VolumeDocAutoCodeEnum.MANUAL.getCode().equals(archRule.getVolAutoCode())) {
      return;
    }
    // 案卷号不为空，并且卷内文件为自动编号或按设置字段编号
    Volume qry = ConvertUtil.toBean(volume, Volume.class);
    ArchCodeVO archCodeVO = archCodeGenCmd.archCode(qry);

    if (ObjectUtil.isEmpty(archCodeVO) || ObjectUtil.isEmpty(archCodeVO.getArchCode())) {
      throw BizTipException.instance(ErrorCode.TIP_INFO, "当前档号获取失败,请检查是否满足分组条件！");
    }

    if (Objects.nonNull(archCodeVO) && !archCodeVO.getArchCode().contains("null")) {
      volume.setArchCode(archCodeVO.getArchCode());
      volume.setVolSequence(archCodeVO.getSequence());
    }
  }

  private Map<String, Object> getSyncVolumeData(
      List<ArchiveRuleFieldListVO> ruleList, Volume volume) {
    Map<String, Object> volumeMap = BeanUtil.beanToMap(volume);
    List<String> fieldSet =
        ruleList.stream()
            .filter(f -> f.getTableId().contains(ArchTmplBO.VOLUME))
            .filter(ArchiveRuleFieldListVO::getEnableGroup)
            .filter(f -> !f.getFieldCode().contains(ArchConst.SEQUENSE))
            .map(rule -> StringUtils.underlineToCamel(rule.getFieldCode()))
            .collect(Collectors.toList());
    return fieldSet.stream()
        .map(
            filed -> {
              Map<String, Object> map = Maps.newHashMap();
              map.put(filed, volumeMap.get(filed));
              return map;
            })
        .flatMap(e -> e.entrySet().stream())
        .collect(HashMap::new, (m, v) -> m.put(v.getKey(), v.getValue()), HashMap::putAll);
  }

  public ArchiveRuleMain getRuleInfo(Long archTypeId, Long projId, Integer year) {
    // 项目下案卷，整理规则以项目整理规则为准
    if (Objects.nonNull(projId)) {
      Project qry = new Project();
      qry.setId(projId);
      ArchiveTypeVO archInfo =
          Optional.ofNullable(archiveTypeSvc.view(archTypeId))
              .orElseThrow(() -> BizTipException.instance(ErrorCode.NOT_FOUND, "未找到门类信息"));
      String projTableId = archInfo.getProjTableId();
      qry.setTableId(projTableId);
      Project project =
          Optional.ofNullable(projectSvc.view(qry))
              .orElseThrow(() -> BizTipException.instance(ErrorCode.NOT_FOUND, "未找到项目信息"));
      Long archRuleId = project.getArchRuleId();
      return archiveRuleMainSvc.getById(archRuleId);
    }
    // 普通案卷
    RuleFieldQueryDTO qryRuleMain = new RuleFieldQueryDTO();
    qryRuleMain.setYear(year);
    qryRuleMain.setArchTypeId(archTypeId);
    ArchiveRuleMainListVO ruleMainByVersion = archiveRuleMainSvc.getRuleMainByVersion(qryRuleMain);
    return ConvertUtil.toBean(ruleMainByVersion, ArchiveRuleMain.class);
  }
}
